Sphere Environment Mapping ist eine schnelle Methode um Reflektionen auf einem matallischen oder reflektierenden Objekt in ihrer Szene hinzuzufügen. Obwohl es nicht so genau wie die Realität oder wie eine Cube Environment Map ist, ist es um einige schneller! Wir werden den Code aus Lektion achtzehn (Quadrics) als Basis für dieses Tutorial verwenden. Außerdem werden wir nicht die selben Textur-Maps verwenden, sondern eine für die Sphere Map und ein Hintergrundbild.
Bevor wir anfangen... Das "Red Book" definiert eine Sphere Map als ein Bild einer Szene auf einem metallischen Ball mit unendlicher Entfernung und unendlichem Brennpunkt. Nun, dass ist unmöglich im reellem Leben. Die beste Möglichkeit die ich gefunden habe, eine gutes Sphere Map Bild zu erzeugen, ohne eine Fisch-Augen-Lense zu benutzen, ist das Programm Adobe Photoshop.
Eine Sphere Map in Photoshop erzeugen:
Als erstes benötigen Sie ein Bild der Umgebung die Sie auf die Sphere mappen wollen. Öffnen Sie das Bild in Adobe Photoshop und markieren Sie das gesamte Bild. Kopieren Sie das Bild und erzeugen Sie ein neues PSD (Photoshop Format), das neue Bild sollte die selbe Größe als das kopierte Bild haben. Fügen Sie eine Kopie des Bildes in das neue Fenster ein, das wir erzeuge haben. Der Grund, warum wir eine Kopie erstellen, ist, dass Photoshop so seine Filter benutzen kann. Anstatt das Bild zu kopieren können Sie aus dem Drop-Down Menü Modus (Mode) auswählen und den RGB-Modus wählen. Dann sollten allen Filter verfügbar sein.
Als nächstes müssen wir die Größe des Bildes verändern, so dass die Bild-Dimensionen ein Vielfaches von 2 sind. Erinnern Sie sich daran, dass ein Bild, wenn es als Textur verwendet werden soll, eine Größe von 128x128, 256x256, etc. haben muss. Im Menü Bild (Image) wählen Sie Bild-Größe (Image Size), deaktivieren die Checkbox Proportionen erzwingen (Constraint Proportions) und ändern die Größe des Bildes auf eine gültige Textur-Größe. Wenn ihr Bild 100x90 groß ist, ist es besser, dass Bild auf 128x128 zu verändern, statt 64x64. Wenn das Bild kleiner gemacht wird, gehen viele Details verloren.
Als letztes wählen wir das Filter-Menü aus, wählen Verzerren (distort) und wenden einen spherischen Modifizieren an. Sie sollten sehen, dass der Mittelpunkt des Bildes ähnlich wie ein Ballon aufgeblasen wird, wobei es bei normalen Sphere Maps die äußere Fläche geschwärzt wird, was aber nichts ausmacht. Speichern Sie eine Kopie des Bildes als .BMP und Sie können anfangen zu programmieren!
Wir fügen diesmal keine neuen globalen Variablen hinzu, aber wir ändern das Textur-Array, damit es 6 Texturen aufnehmen kann.
GLuint texture[6]; // Speicher für 6 Texturen
int LoadGLTextures() // Lade Bitmaps und konvertiere sie in Texturen
{
int Status=FALSE; // Status Indikator
AUX_RGBImageRec *TextureImage[2]; // erzeuge Speicherplatz für die Textur
memset(TextureImage,0,sizeof(void *)*2); // Setze den Zeiger auf NULL
// Lade Bitmap, überprüfe auf Fehler, wenn Bitmap nicht gefunden, beenden
if ((TextureImage[0]=LoadBMP("Data/BG.bmp")) && // Hintergrund Textur
(TextureImage[1]=LoadBMP("Data/Reflect.bmp"))) // Reflektions Textur (Spheremap)
{
Status=TRUE; // Setze den Status auf TRUE
glGenTextures(6, &texture[0]); // erzeuge drei Texturen
for (int loop=0; loop<=1; loop++)
{
// erzeuge die am nähsten gelegene gefilterte Textur
glBindTexture(GL_TEXTURE_2D, texture[loop]); // erzeuge Textur 0 und 1
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[loop]->sizeX, TextureImage[loop]->sizeY,
0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[loop]->data);
// erzeuge linear gefilterte Textur
glBindTexture(GL_TEXTURE_2D, texture[loop+2]); // erzeuge Textur 2, 3 und 4
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[loop]->sizeX, TextureImage[loop]->sizeY,
0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[loop]->data);
// erzeuge MipMapped Textur
glBindTexture(GL_TEXTURE_2D, texture[loop+4]); // erzeuge Textur 4 und 5
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[loop]->sizeX, TextureImage[loop]->sizeY,
GL_RGB, GL_UNSIGNED_BYTE, TextureImage[loop]->data);
}
for (loop=0; loop<=1; loop++)
{
if (TextureImage[loop]) // Wenn Textur Existiert
{
if (TextureImage[loop]->data) // Wenn Textur Image Existiert
{
free(TextureImage[loop]->data); // Gebe Textur Image Speicher frei
}
free(TextureImage[loop]); // Gebe Image Struktur frei
}
}
}
return Status; // Gebe Status zurück
}
GLvoid glDrawCube()
{
glBegin(GL_QUADS);
// Frontseite
glNormal3f( 0.0f, 0.0f, 0.5f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
// Rückseite
glNormal3f( 0.0f, 0.0f,-0.5f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
// obere Seite
glNormal3f( 0.0f, 0.5f, 0.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
// untere Seite
glNormal3f( 0.0f,-0.5f, 0.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
// rechte Seite
glNormal3f( 0.5f, 0.0f, 0.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
// linke Seite
glNormal3f(-0.5f, 0.0f, 0.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glEnd();
}
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); // Setze den Textur-Erzeugungs-Modus für S auf Sphere Mapping ( NEU ) glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); // Setze den Textur-Erzeugungs-Modus für T auf Sphere Mapping ( NEU )
int DrawGLScene(GLvoid) // Hier kommt der ganze Zeichnen-Kram hin
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Lösche den Bildschirm und den Depth-Buffer
glLoadIdentity(); // Resette die Ansicht (View)
glTranslatef(0.0f,0.0f,z);
glEnable(GL_TEXTURE_GEN_S); // aktiviert Textur Koordinaten Erzeugung für S ( NEU )
glEnable(GL_TEXTURE_GEN_T); // aktiviert Textur Koordinaten Erzeugung für T ( NEU )
glBindTexture(GL_TEXTURE_2D, texture[filter+(filter+1)]); // Wählt eine Sphere Map aus
glPushMatrix();
glRotatef(xrot,1.0f,0.0f,0.0f);
glRotatef(yrot,0.0f,1.0f,0.0f);
switch(object)
{
case 0:
glDrawCube();
break;
case 1:
glTranslatef(0.0f,0.0f,-1.5f); // zentriere den Zylinder
gluCylinder(quadratic,1.0f,1.0f,3.0f,32,32); // Ein Zylinder mit einem Radius von 0.5 und einer Höhe von 2
break;
case 2:
gluSphere(quadratic,1.3f,32,32); // Sphere mit einem Radius von 1 und 16 Segmente für Breite/Länge
break;
case 3:
glTranslatef(0.0f,0.0f,-1.5f); // Zentriere den Kegel
gluCylinder(quadratic,1.0f,0.0f,3.0f,32,32); // Kegel mit einem Boden-Radius von 0.5 und einer Höhe von 2
break;
};
glPopMatrix();
glDisable(GL_TEXTURE_GEN_S); // deaktiviert Textur Koordinaten Erzeugung ( NEU )
glDisable(GL_TEXTURE_GEN_T); // deaktiviert Textur Koordinaten Erzeugung ( NEU )
glBindTexture(GL_TEXTURE_2D, texture[filter*2]); // Wählt die Hintergrund Textur aus ( NEU )
glPushMatrix();
glTranslatef(0.0f, 0.0f, -24.0f);
glBegin(GL_QUADS);
glNormal3f( 0.0f, 0.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-13.3f, -10.0f, 10.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 13.3f, -10.0f, 10.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 13.3f, 10.0f, 10.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-13.3f, 10.0f, 10.0f);
glEnd();
glPopMatrix();
xrot+=xspeed;
yrot+=yspeed;
return TRUE; // Weiter geht's
}
if (keys[' '] && !sp)
{
sp=TRUE;
object++;
if(object>3)
object=0;
}
// Shutdown gluDeleteQuadric(quadratic); KillGLWindow(); // Kill das Fenster return (msg.wParam); // Beende das Programm }